﻿using System;
using Didaku.Electronics.Collections;
using Didaku.Electronics.Exceptions;

namespace Didaku.Electronics.Helper
{
    /// <summary>一个面向电阻值分解的封装类
    /// </summary>
    public class ResistanceValueResolve
    {
        /// <summary>一个面向电阻值分解的封装类
        /// </summary>
        public ResistanceValueResolve()
        {
            CircuitType = CircuitType.Series;
        }

        /// <summary>已存在的电阻的集合
        /// </summary>
        public Resistances Existing { get; set; }

        /// <summary>电阻的组合方式: 仅串联,仅并联,串并混合, 默认仅串联。
        /// </summary>
        public CircuitType CircuitType { get; set; }

        /// <summary>将指定的电阻值从已存在的电阻集合中搜索最合适的电阻进行组合，并返回最合适的电阻的集合
        /// </summary>
        /// <param name="result">返回的结果，最合适的电阻的集合</param>
        /// <param name="target">指定的需分解的电阻值,单位欧姆(Ω)</param>
        /// <param name="begin">已存在的集合的起始位置，默认从0的位置开始搜索</param>
        /// <returns>分解剩余的阻值余数</returns>
        public float TryGetResolveResult(ref Resistances result, float target, int begin = 0)
        {
            if (Existing == null || Existing.Count <= 0)
                throw ResistanceCollectionException.ForNull();
            if (target < 0)
                throw new ArgumentException("需分解的电阻值不能小于零.");

            //分解剩余的阻值余数
            float remainder = target;

            switch (CircuitType)
            {
                case CircuitType.Paralleling:
                    remainder = TryGetParallelingResolveResult(ref result, remainder, begin);
                    break;
                case CircuitType.Blend:
                    remainder = TryGetBlendResolveResult(ref result, remainder, begin);
                    break;
                case CircuitType.Series:
                default:
                    remainder = TryGetSeriesResolveResult(ref result, remainder, begin);
                    break;
            }
            return remainder;
        }

        /// <summary>按混合电路进行分解
        /// </summary>
        /// <param name="result">返回的结果，最合适的电阻的集合</param>
        /// <param name="target">指定的需分解的电阻值,单位欧姆(Ω)</param>
        /// <param name="begin">已存在的集合的起始位置，默认从0的位置开始搜索</param>
        /// <returns>分解剩余的阻值余数</returns>
        protected float TryGetBlendResolveResult(ref Resistances result, float target, int begin)
        {
            throw new NotImplementedException();
        }

        /// <summary>按并联电路进行分解
        /// </summary>
        /// <param name="result">返回的结果，最合适的电阻的集合</param>
        /// <param name="target">指定的需分解的电阻值,单位欧姆(Ω)</param>
        /// <param name="begin">已存在的集合的起始位置，默认从0的位置开始搜索</param>
        /// <returns>分解剩余的阻值余数</returns>
        protected float TryGetParallelingResolveResult(ref Resistances result, float target, int begin)
        {
            throw new NotImplementedException();
        }

        /// <summary>按串联电路进行分解
        /// </summary>
        /// <param name="result">返回的结果，最合适的电阻的集合</param>
        /// <param name="target">指定的需分解的电阻值,单位欧姆(Ω)</param>
        /// <param name="begin">已存在的集合的起始位置，默认从0的位置开始搜索</param>
        /// <returns>分解剩余的阻值余数</returns>
        protected float TryGetSeriesResolveResult(ref Resistances result, float target, int begin)
        {
            //下面代码中我们称已存在的电阻的集合为“数列”，并假定该数列已按大到小进行过排序
            for (int i = begin; i < Existing.Count; i++)
            {
                if (target <= 0) //当递归时回归主函数时
                    break;
                if (target < Existing[i].Value) //如果目标值小于集合当前值，继续向数列下一个进行寻找合适值
                    continue;
                var res = Existing[i];
                if (target/res.Value > 1)
                {
                    var count = (int) (target/res.Value);
                    for (int j = 0; j < count; j++)
                    {
                        result.Add((Resistance) res.Clone());
                        target -= res.Value;
                    }
                }
                //余数进行下一步的递归分解
                var modular = target%res.Value;
                if (modular > 0)
                {
                    //递归分解
                    target = TryGetSeriesResolveResult(ref result, modular, i);
                }
                else
                {
                    break;
                }
            }
            return target;
        }
    }
}
